package Physics;
/**
 Holds a three degrees of freedom for orientation.
 Quaternions have several mathematical properties that make them 
 useful for representing orientations, but require four items of data to
 hold the three degrees of freedom. These four items of data can
 be viewed as the coefficients of a complex number with three
 imaginary parts. The mathematics of the quaternion is then
 defined and is roughly correspondent to the math of 3D
 rotations. A quaternion is only a valid rotation if it is
 normalised: i.e. it has a length of 1.

 @note Angular velocity and acceleration can be correctly
 represented as vectors. Quaternions are only needed for
 orientation.
*/
public class Quaternion {
	public float r; /** real component */
	public float i; /** first imaginary component */
	public float j; /** second imaginary component */
	public float k; /** third imaginary component */
	
	/** default Quarternion. Zero rotation. */
	Quaternion() {
		r = 1;
		i = 0;
		j = 0;
		k = 0;
		}
	
	/** Note: Quaternion needs to be normalized if the given values
	are to be a valid rotation */
	Quaternion(float a_r, float a_i, float a_j, float a_k){
		r = a_r;
		i = a_i;
		j = a_j;
		k = a_k;
	}
	
	Quaternion(Quaternion other)
	{
		r = other.r;
		i = other.i;
		j = other.j;
		k = other.k;
	}
	
	/** normalizes the Quarternion to a valid length so it can be used. */
	void normalize(){
		float d = r * r + i * i + j * j + k * k;
		/** Check for zero length quaternion, and use the no-rotation
        quaternion in that case. */
		if(d == 0){
			r = 1;
			return;
		}
		d = ((float)1.0 / (float)Math.sqrt(d));
		r *= d;
		i *= d;
		j *= d;
		k *= d;
	}
	/** Multiplies Quaternions	*/
	void multiplyByQuaternion(Quaternion multiplier){
		Quaternion temp = new Quaternion(r, i, j, k);
		r = 	temp.r * multiplier.r - temp.i * multiplier.i - 
				temp.j * multiplier.j - temp.k * multiplier.k;
		
		i = 	temp.r * multiplier.i + temp.i * multiplier.r + 
				temp.j * multiplier.k - temp.k * multiplier.j;
		
		j = 	temp.r * multiplier.j + temp.j * multiplier.r + 
				temp.k * multiplier.i - temp.i * multiplier.k;

		k = 	temp.r * multiplier.k + temp.k * multiplier.r + 
				temp.i * multiplier.j - temp.j * multiplier.i;
	} 
	/** adds a scaled vector to this quarternion. Used to update
	an orientation by a vector wrt time */
	void addScaledVector(Vector3 vector, float scale)
	{
		Quaternion temp = new Quaternion(0,vector.x * scale, vector.y * scale, vector.z * scale);
		temp.multiplyByQuaternion(this);
		r += temp.r * ((float).5);
		i += temp.i * ((float).5);
		j += temp.j * ((float).5);
		k += temp.k * ((float).5);
	}
	/** rotate this quarternion by a vector */
	void rotateByVector(Vector3 vector){
		Quaternion q = new Quaternion(0,vector.x,vector.y,vector.z);
		multiplyByQuaternion(q);
	}
}
		